/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author            Notes
 * 2020-05-28     Ghazi          the first version
 */
#include <rtthread.h>
#include <board.h>

#if defined(RT_USING_W25QXX) || defined(RT_USING_SFUD)
    #include <drv_qspi.h>
    #include <drv_spi.h>
#ifdef RT_USING_W25QXX
    #include "spi_flash_w25qxx.h"
#elif defined(RT_USING_SFUD)
    #include "string.h"
    #include "spi_flash.h"
    #include "spi_flash_sfud.h"
    sfud_flash sfud_norflash;
    sfud_flash sfud_spiflash;
    rt_spi_flash_device_t spi_device;
    rt_spi_flash_device_t qspi_device;
#endif

int nor_flash_enter_qspi_mode(struct rt_qspi_device * device)
{
    uint8_t cmd_data[2] = {SFUD_CMD_WRITE_STATUS_REGISTER};
    struct rt_qspi_message message = {0};

    /* QSPI enable quad */
    if(rt_qspi_send(device, &cmd_data[0], 1) < 0)
    {
        rt_kprintf("enable qspi failed\n");
        return -RT_ERROR;
    }

    /* Enter QPI Mode*/
    cmd_data[0] = 0x38;
    if(rt_qspi_send(device, &cmd_data[0], 1) < 0)
    {
        rt_kprintf("enter qspi mode failed\n");
        return -RT_ERROR;
    }

    /* Set Max read freq */
    cmd_data[0] = 0xC0;
    cmd_data[1] = 3<<4;

    message.instruction.content = cmd_data[0];
    message.instruction.qspi_lines = 4;
    message.dummy_cycles = 0;
    message.qspi_data_lines = 4;

    /* set send buf and send size */
    message.parent.send_buf = &cmd_data[1];
    message.parent.recv_buf = RT_NULL;
    message.parent.length = 1;
    message.parent.cs_take = 1;
    message.parent.cs_release = 1;

    if(rt_qspi_transfer_message(device, &message) < 0)
    {
        rt_kprintf("set max freq failed\n");
        return -RT_ERROR;
    }
    else
        return RT_EOK;
}

int nor_flash_exit_qspi_mode(struct rt_qspi_device * device)
{
//    struct rt_qspi_message message = {0};
    rt_uint8_t recv[3] = {0};

//    rt_uint8_t cmd_data = 0xff;
//    if(rt_qspi_send(device, &cmd_data, 1) < 0)
//    {
//        rt_kprintf("exit qspi mode failed\n");
//        return -RT_ERROR;
//    }

    uint8_t cmd_data[2] = {SFUD_CMD_WRITE_STATUS_REGISTER};
    struct rt_qspi_message message = {0};

    /* QSPI enable quad */
    if(rt_qspi_send(device, &cmd_data[0], 1) < 0)
    {
        rt_kprintf("enable qspi failed\n");
        return -RT_ERROR;
    }
    message.instruction.content = 0x9f;
    message.instruction.qspi_lines = 4;
    message.dummy_cycles = 0;
    message.qspi_data_lines = 4;

    /* set send buf and send size */
    message.parent.send_buf = RT_NULL;
    message.parent.recv_buf = &recv;
    message.parent.length = 3;
    message.parent.cs_take = 1;
    message.parent.cs_release = 1;

    message.instruction.content = 0x9f;
    message.instruction.qspi_lines = 4;

    /* set send buf and send size */
    message.parent.send_buf = RT_NULL;
    message.parent.recv_buf = &recv;
    message.parent.length = 3;

    rt_enter_critical();
    if(rt_qspi_transfer_message(device, &message) < 0)
    {
        rt_kprintf("write enable failed\n");
        goto err;
    }
    rt_kprintf("0x%02x%02x%02x\n",recv[0],recv[1],recv[2]);
    message.instruction.content = 0x66;
    if(rt_qspi_transfer_message(device, &message) < 0)
    {
        rt_kprintf("write enable failed\n");
        goto err;
    }

    message.instruction.content = 0x99;
    if(rt_qspi_transfer_message(device, &message) < 0)
    {
        rt_kprintf("exit qspi mode failed\n");
        goto err;
    }
    else
    {
        rt_thread_mdelay(1);
        rt_exit_critical();
        return RT_EOK;
    }

err:
    rt_exit_critical();
    return -RT_ERROR;
}

//int nor_flash_memory_mapped_mode(struct rt_qspi_device * device)
//{
//    QSPI_CommandTypeDef      s_command;
//    QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
//
//    /* Configure the command for the read instruction */
//    s_command.InstructionMode   = QSPI_INSTRUCTION_4_LINES;
//    s_command.Instruction       = SFUD_CMD_QUAD_IO_READ_DATA;
//    s_command.AddressMode       = QSPI_ADDRESS_4_LINES;
//    s_command.AddressSize       = QSPI_ADDRESS_24_BITS;
//    s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
//    s_command.DataMode          = QSPI_DATA_4_LINES;
//    s_command.DummyCycles       = 8;
//    s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;
//    s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
//    s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;
//
//    /* Configure the memory mapped mode */
//    s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_ENABLE;
//    s_mem_mapped_cfg.TimeOutPeriod     = 1;
//
//    if (HAL_QSPI_MemoryMapped((QSPI_HandleTypeDef *)(device->parent.bus->parent.user_data), &s_command, &s_mem_mapped_cfg) != HAL_OK)
//    {
//        rt_kprintf("memory mapped mode failed\n");
//        return RT_ERROR;
//    }
//    else
//        return RT_EOK;
//}


int rt_flash_init(void)
{
    stm32_qspi_bus_attach_device("qspi1","norspi", RT_NULL, 1, RT_NULL, RT_NULL);
    rt_hw_spi_device_attach("spi2", "w25q64", GPIOC, GPIO_PIN_0);
//    struct rt_qspi_device * device = (struct rt_qspi_device *)rt_device_find("norspi");
//    nor_flash_exit_qspi_mode(device);
//    rt_thread_mdelay(1);
#ifdef RT_USING_W25QXX
    return w25qxx_init("norflash0", "norspi");
#elif defined(RT_USING_SFUD)
    spi_device = rt_sfud_flash_probe("spiflash", "w25q64");
    if (spi_device == RT_NULL)
    {
        return -RT_ERROR;
    }
    memcpy(&sfud_spiflash, spi_device->user_data, sizeof(sfud_flash));

    qspi_device = rt_sfud_flash_probe("norflash", "norspi");
    if (qspi_device == RT_NULL)
    {
        return -RT_ERROR;
    }
    memcpy(&sfud_norflash, qspi_device->user_data, sizeof(sfud_flash));
    return 0;
#endif
}
INIT_PREV_EXPORT(rt_flash_init);

#endif
